﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
using System.ComponentModel;

namespace SMS_Server
{

    public class GSMManager
    {
        public List<SMSMessage> RecivedMessages = new List<SMSMessage>();
        public List<SMSMessage> SendingMessages = new List<SMSMessage>();
        /// <summary>
        /// Initializes the GSMManager
        /// </summary>
        public GSMManager()
        {

        }

        bool GO = false;
        bool OK = false;
        bool ERROR = false;
        public System.IO.Ports.SerialPort comPort = new System.IO.Ports.SerialPort();
        //public void Send
        public bool SMSEnable = true;
        public string DeviceIdentity = "";
        public string Manufacturer = "";
        public string Model = "";
        public string IMEI = "";
        public string MyNumber = "";
        public int SignalStrength;
        //Just to expose system status
        public bool SystemConfigured = false;


        /// <summary>
        /// Configers the GSMManager to use an specific port
        /// </summary>
        /// <param name="PortName"></param>
        /// <returns></returns>
        public bool SMSConfig(string PortName)
        {
            if (comPort.IsOpen == false)
            {
                comPort.PortName = PortName;
                comPort.BaudRate = 115200;
                comPort.Parity = Parity.None;
                comPort.StopBits = StopBits.One;
                comPort.DataBits = 8;
                comPort.ReadBufferSize = 10000;
                comPort.ReadTimeout = 1000;
                comPort.WriteBufferSize = 10000;
                comPort.WriteTimeout = 10000;

                try { comPort.Open(); }
                catch //(Exception ex)
                {

                    if (SMSEnable == true)
                    {
                        SMSEnable = false;
                        SystemConfigured = false;
                        return false;//throw (new Exception("Port(" + comPort.PortName + ") Could not be Opened \n\r Check your GSM Device Connection", ex));
                    }
                    SMSEnable = false;
                    SystemConfigured = false;
                    return false;
                }

                comPort.RtsEnable = true;
                comPort.DataReceived += new SerialDataReceivedEventHandler(ReadSerialData);
            }
            if (comPort.IsOpen == true)
            {
                //Detach event handler
                comPort.DataReceived -= new SerialDataReceivedEventHandler(ReadSerialData);
                comPort.RtsEnable = false;
                comPort.Close();
                //Configure new COM port
                comPort.PortName = PortName;
                comPort.BaudRate = 115200;
                comPort.Parity = Parity.None;
                comPort.StopBits = StopBits.One;
                comPort.DataBits = 8;
                comPort.ReadBufferSize = 10000;
                comPort.ReadTimeout = 1000;
                comPort.WriteBufferSize = 10000;
                comPort.WriteTimeout = 10000;

                try { comPort.Open(); }
                catch //(Exception ex)
                {

                    if (SMSEnable == true)
                    {
                        SMSEnable = false;
                        SystemConfigured = false;
                        return false; //throw (new Exception("Port(" + comPort.PortName + ") Could not be Opened \n\r Check your GSM Device Connection", ex));
                    }
                        SystemConfigured = false;
                    SMSEnable = false;
                    return false;
                }

                comPort.RtsEnable = true;
                comPort.DataReceived += new SerialDataReceivedEventHandler(ReadSerialData);

            }
            comPort.DiscardInBuffer();
            comPort.DiscardOutBuffer();

            /// Configure to SMS text Mode
            comPort.Write("AT+CMGF=1" + (char)13);
            ///

            GO = false; ERROR = false; OK = false;
            for (int i = 0; i < 100; i++)
            {
                if (OK == true)
                    break;
                if (ERROR == true)
                {
                    SMSEnable = false;
                    SystemConfigured = false;
                    return false;
                }
                System.Threading.Thread.Sleep(15); if (i == 100) { ERROR = true; SMSEnable = false; return false; }
            }

            Readed = "";

            /// Request Device Identity
            comPort.Write("ATI0" + (char)13);
            ///

            GO = false; ERROR = false; OK = false;
            for (int i = 0; i < 100; i++)
            {
                if (OK == true)
                    break;
                if (ERROR == true)
                {
                    SMSEnable = false;
                    SystemConfigured = false;
                    return false;
                }
                System.Threading.Thread.Sleep(15); if (i == 100) { ERROR = true; SMSEnable = false; return false; }
            }
            //Set device Identity
            DeviceIdentity = Readed;
            Readed = "";

            try
            {
            string Tempstring = DeviceIdentity.Substring(DeviceIdentity.IndexOf("\n"));
            Tempstring = Tempstring.Substring(0, Tempstring.IndexOf("OK"));
            Tempstring = Tempstring.Trim();
            string[] BaseSplit = Tempstring.Split('\n');
            Dictionary<string, string> Information = new Dictionary<string, string>();
            foreach (string str in BaseSplit)
            {
                string[] SubSplit = str.Split(':'); if (SubSplit.Length != 2) continue;
                Information.Add(SubSplit[0].Trim(), SubSplit[1].Trim());
            }
            DeviceIdentity = Tempstring;
                Manufacturer = Information["Manufacturer"];
                Model = Information["Model"];
                IMEI = Information["IMEI"];
            }
            catch
            {
                SMSEnable = false;
                SystemConfigured = false;
                return false;
            }

            MyNumber = GetMyNumber();
            SignalStrength = GetSignalStrength();

            SMSEnable = true;
            SystemConfigured = true;
            return true;
        }

        public void Close()
        {
            if (comPort.IsOpen == false)
                return;
            else
            {
                //Detach event handler
                SystemConfigured = false;
                comPort.DataReceived -= new SerialDataReceivedEventHandler(ReadSerialData);
                comPort.RtsEnable = false;
                comPort.Close();
            }
        }

        void SMS_is_Disable()
        {

        }

        /// <summary>
        /// Read my number from the sim
        /// </summary>
        /// <returns></returns>
        public string GetMyNumber()
        {
            DateTime t1 = DateTime.Now;
            Readed = "";

            SMS_is_Disable();

            ///
            comPort.Write("AT+CNUM" + (char)13);
            ///

            //Waiting for response
            GO = false; ERROR = false; OK = false;
            for (int i = 0; i < 100; i++)
            {
                if (OK == true)
                    break;
                if (ERROR == true)
                {
                    return null;
                }
                System.Threading.Thread.Sleep(15); if (i == 100) ERROR = true;
            }

            string number = Readed;
            Readed = "";

            number = number.Substring(number.IndexOf("\n"));
            number = number.Substring(0, number.IndexOf("OK"));
            number = number.Trim();
            number = number.Replace("\"", "");
            number = number.Substring(number.IndexOf("My Number"));
            string[] spltd = number.Split(',');
            number = spltd[1];

            return number;
        }

        /// <summary>
        /// Get the signal strength
        /// </summary>
        /// <returns></returns>
        public int GetSignalStrength()
        {

            DateTime t1 = DateTime.Now;
            Readed = "";

            SMS_is_Disable();

            ///
            comPort.Write("AT+CSQ" + (char)13);
            ///

            //Waiting for response
            GO = false; ERROR = false; OK = false;
            for (int i = 0; i < 100; i++)
            {
                if (OK == true)
                    break;
                if (ERROR == true)
                {
                    return 0;
                }
                System.Threading.Thread.Sleep(15); if (i == 100) ERROR = true;
            }

            string strength = Readed;
            Readed = "";

            strength = strength.Substring(strength.IndexOf("\n"));
            strength = strength.Substring(0, strength.IndexOf("OK"));
            strength = strength.Trim();
            string[] spltd = strength.Split(':');
            strength = spltd[1].Split(',')[0];

            int power = 0;
            if (strength == "99")
            { power = 0; }
            else { try { int powerparam = int.Parse(strength); power = (100 / 31) * powerparam; } catch { power = 0; } }
            SignalStrength = power;
            return power;
        }

        /// <summary>
        /// Reads an existing SMS by index from the device
        /// </summary>
        /// <param name="MessageIndex"></param>
        /// <returns></returns>
        public SMSMessage ReadExistingSMS(int MessageIndex)
        {
            DateTime t1 = DateTime.Now;
            Readed = "";

            SMS_is_Disable();

            ///
            comPort.Write("AT+CMGR=" + MessageIndex.ToString() + (char)13);
            ///

            //Waiting for response
            GO = false; ERROR = false; OK = false;
            for (int i = 0; i < 100; i++)
            {
                if (OK == true)
                    break;
                if (ERROR == true)
                {
                    return null;
                }
                System.Threading.Thread.Sleep(15); if (i == 100) ERROR = true;
            }

            SMSMessage msg = new SMSMessage();
            int k = 0;
            bool msgErr = false;
            int l = 0;
            for (int j = 0; j < 3; j++)
            {
                if (k == -1 || l == -1) { msgErr = true; continue; }
                k = Readed.IndexOf("\"", l);
                if (k == -1 || l == -1) { msgErr = true; continue; }
                l = Readed.IndexOf("\"", k + 1);
                if (k == -1 || l == -1) { msgErr = true; continue; }
                string inc = Readed.Substring(k + 1, l - k - 1);
                if (j == 1 && msgErr == false)
                    msg.PhoneNo = inc;
                if (j == 2 && msgErr == false)
                    msg.Time = DateTime.Parse(inc);

                l++;
            }


            if (msgErr == false)
            {
                msg.Message = Readed.Substring(l + 2, Readed.Length - l - 2 - 8);
                msg.Status = SMSMessage.SMSMessageStatus.Recived;

                DateTime t2 = DateTime.Now;
                return msg;
            }

            return null;
        }
        /// <summary>
        /// Enumarets the Incoming SMS type, say Read, unread etc
        /// </summary>
        public enum ReadIncommingSMSType
        {
            REC_UNREAD = 0,
            REC_READ = 1,
            STO_UNSENT = 2,
            STO_SENT = 3,
            ALL = 4
        }
        /// <summary>
        /// Deletes an SMS by index from the device
        /// </summary>
        /// <param name="index"></param>
        public void DeleteExistingSMS(int index)
        {
            SMS_is_Disable();
            Readed = "";

            comPort.Write("AT+CMGD=" + index.ToString() + (char)13);


            GO = false; ERROR = false; OK = false;
            for (int i = 0; i < 100; i++)
            {
                if (OK == true)
                    break;
                if (ERROR == true)
                {
                    return;
                }
                System.Threading.Thread.Sleep(15); if (i == 100) ERROR = true;
            }
        }
        /// <summary>
        /// Sends a SMS
        /// </summary>
        /// <param name="sms"></param>
        /// <returns></returns>
        public string SendSMS(SMSMessage sms)
        {
            return SendSMS(sms.PhoneNo, sms.Message);
        }
        /// <summary>
        /// Sends a SMS
        /// </summary>
        /// <param name="PhoneNo"></param>
        /// <param name="Message"></param>
        /// <returns></returns>
        public string SendSMS(string PhoneNo, string Message)
        {
            SMS_is_Disable();
            string s = "";
            Readed = "";

            ///
            comPort.Write("AT+CMGS=\"" + PhoneNo + "\"" + (char)13);
            ///

            GO = false; ERROR = false; OK = false;
            for (int i = 0; i < 100; i++)
            {
                if (OK == true)
                    break;
                if (ERROR == true)
                {
                    return "ERROR";
                }
                System.Threading.Thread.Sleep(15); if (i == 100) ERROR = true;
            }

            s += "\r" + Readed;
            Readed = "";
            ///
            comPort.Write(Message + (char)26);// Char.ConvertFromUtf32(26));
            ///

            GO = false; ERROR = false; OK = false;
            for (int i = 0; i < 100; i++)
            {
                if (OK == true)
                {
                    break;
                }
                if (ERROR == true)
                {
                    return "ERROR";
                }
                System.Threading.Thread.Sleep(15); if (i == 100) ERROR = true;
            }

            s += "\r" + Readed;

            return s;
        }
        /// <summary>
        /// Reads SMS from the device
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public List<SMSMessage> ReadIncommingSMS(ReadIncommingSMSType type)
        {
            DateTime t1 = DateTime.Now;
            Readed = "";
            SMS_is_Disable();
            if (SMSEnable == false) return null;

            switch (type)
            {

                case ReadIncommingSMSType.STO_SENT:
                    comPort.Write("AT+CMGL=\"STO SENT\"" + (char)13);
                    break;
                case ReadIncommingSMSType.REC_UNREAD:
                    comPort.Write("AT+CMGL=\"REC UNREAD\"" + (char)13);
                    break;
                case ReadIncommingSMSType.ALL:
                    comPort.Write("AT+CMGL=\"ALL\"" + (char)13);
                    break;
                case ReadIncommingSMSType.REC_READ:
                    comPort.Write("AT+CMGL=\"REC READ\"" + (char)13);
                    break;
                case ReadIncommingSMSType.STO_UNSENT:
                    comPort.Write("AT+CMGL=\"STO UNSENT\"" + (char)13);
                    break;
            }

            GO = false; ERROR = false; OK = false;
            for (int i = 0; i < 100; i++)
            {
                if (OK == true)
                    break;
                if (ERROR == true)
                {
                    //MessageBox.Show("ERROR");
                    return null;
                }
                System.Threading.Thread.Sleep(15); if (i == 100) { ERROR = true; this.SMSEnable = false; return null; }

            }

            List<SMSMessage> messList = new List<SMSMessage>();

            string[] re = Readed.Split(new string[] { "+CMGL:" }, StringSplitOptions.RemoveEmptyEntries);
            Readed = "";

            for (int i = 1; i < re.Length; i++)
            {
                int k = 0;
                bool messErr = false;
                int l = 0;
                string Str = re[i];
                SMSMessage mess = new SMSMessage();
                string ind = Str.Substring(0, Str.IndexOf(",")).Trim();
                mess.index = int.Parse(ind);
                for (int j = 0; j < 3; j++)
                {
                    if (k == -1 || l == -1) { messErr = true; continue; }
                    k = Str.IndexOf("\"", l);
                    if (k == -1 || l == -1) { messErr = true; continue; }
                    l = Str.IndexOf("\"", k + 1);
                    if (k == -1 || l == -1) { messErr = true; continue; }
                    string inc = Str.Substring(k + 1, l - k - 1);
                    if (j == 1 && messErr == false)
                        mess.PhoneNo = inc;
                    if (j == 2 && messErr == false)
                        mess.Time = DateTime.Parse(inc);

                    l++;
                }
                if (messErr == false)
                {
                    mess.Message = Str.Substring(l + 2, Str.Length - l + 2 - 8 + 2);
                    mess.Message = mess.Message.Replace("\r\nOK", "");
                    mess.Status = SMSMessage.SMSMessageStatus.Recived;
                    messList.Add(mess);
                }


            }
            return messList;
        }
        /// <summary>
        /// The string read from the COM port
        /// </summary>
        private string Readed = "";
        /// <summary>
        /// Reads data from the com port
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ReadSerialData(object sender, SerialDataReceivedEventArgs e)
        {
            System.IO.Ports.SerialPort SP = (System.IO.Ports.SerialPort)sender;
            string s = SP.ReadExisting();
            Readed += s;
            if (Readed.EndsWith("OK\r\n") || Readed.EndsWith("\r\n> ") || Readed.EndsWith(((char)26).ToString()))
                OK = true;
            if (Readed.EndsWith("ERROR\r\n"))
                ERROR = true;
        }

    }

}
